Completed
Push — master ( 055e4a...58b779 )
by Kyungmi
07:54 queued 05:37
created

Model.js ➔ ???   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 3
nc 4
nop 2
dl 0
loc 13
ccs 5
cts 7
cp 0.7143
crap 3.2098
rs 9.4285
c 4
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
A Model.js ➔ ... ➔ ??? 0 1 1
1
/**
2
 * Abstract Model class interacting with MongoDB
3
 *
4
 * @since 1.0.0
5
 */
6
7 4
const co = require('co');
8 4
const mongodb = require('mongodb');
9 4
const config = require('../config/server.config');
10 4
const SSSError = require('../common/Error');
11
12 4
const MongoClient = mongodb.MongoClient;
13 4
const ObjectID = mongodb.ObjectID;
14 4
const url = process.env.MONGODB_URI || config.defaults.mongoDBUrl;
15 4
const logger = require('winston');
16
17
/**
18
 * @class
19
 * @classdesc basic interactions with selected collection
20
 */
21
class Model {
22
  constructor(collection, indexes) {
23 16
    if (new.target === Model) {
24
      throw new TypeError('Cannot construct Model instances directly');
25
    }
26
27 16
    this.collection = collection || this.constructor.name.toLowerCase();
28
29 16
    if (indexes instanceof Array) {
30 16
      this.runQuery(col => col.createIndexes(indexes))
31 16
        .then(() => logger.log(`[DB] ${this.collection}'s index creation is successfully done.`))
32
        .catch(error => logger.error(`[DB] ${this.collection}'s index creation is failed.`, error));
33
    }
34
  }
35
36
  runQuery(fn) {
37 107
    const self = this;
38 107
    return co(function* run() {
39 107
      const db = yield MongoClient.connect(url);
40 107
      const collection = db.collection(self.collection);
41 107
      const result = yield fn.call(self, collection);
42 107
      yield db.close();
43 107
      return result;
44
    }).catch((err) => {
45
      throw err;
46
    });
47
  }
48
49
  find(query, sort, skip, limit) {
50 26
    if (query && query._id) {
51 8
      query._id = ObjectID(query._id);
52
    }
53 26
    return this.runQuery((collection) => {
54 26
      const cursor = collection.find(query || {}).sort(sort || {});
55 26
      if (typeof skip !== 'undefined' || typeof limit !== 'undefined') {
56
        cursor.skip(skip).limit(limit);
57
      }
58 26
      return cursor.toArray();
59 26
    }).then(list => list.map((item) => {
60 37
      item._id = item._id.toHexString();
61 37
      return item;
62
    })).catch((error) => {
63
      logger.error(error);
64
      throw new SSSError(SSSError.Types.DB, {}, error);
65
    });
66
  }
67
68
  count(query) {
69 12
    return this.runQuery(collection => collection.count(query || {}))
70
      .catch((error) => {
71
        logger.error(error);
72
        throw new SSSError(SSSError.Types.DB, {}, error);
73
      });
74
  }
75
76
  add(model) {
77 26
    return this.runQuery(collection => collection.insertOne(model))
78
      .then((result) => {
79 26
        let data = result.ops;
80 26
        if (data) {
81 26
          data = result.ops.map(d => Object.assign({}, d, { _id: d._id.toHexString() }));
82
        }
83 26
        return { data, count: result.result.n };
84
      })
85
      .catch((error) => {
86
        logger.error(error);
87
        throw new SSSError(SSSError.Types.DB, {}, error);
88
      });
89
  }
90
91
  update(id, model, unset) {
92 8
    return this.updateWithQuery({ _id: ObjectID(id) }, model, unset);
93
  }
94
95
  updateWithQuery(query, model, unset) {
96 9
    const option = { $set: model };
97 9
    if (unset) {
98 3
      option.$unset = unset;
99
    }
100 9
    return this.runQuery(collection => collection.findOneAndUpdate(query, option))
101
102 9
      .then(result => ({ data: [{ _id: result.value._id.toHexString() }], count: 1 }))
103
      .catch((error) => {
104
        logger.error(error);
105
        throw new SSSError(SSSError.Types.DB, {}, error);
106
      });
107
  }
108
109
  remove(id) {
110 18
    return this.runQuery(collection => collection.deleteOne({ _id: ObjectID(id) }))
111 18
      .then(result => ({ data: [{ _id: id }], count: result.result.n }))
112
      .catch((error) => {
113
        logger.error(error);
114
        throw new SSSError(SSSError.Types.DB, {}, error);
115
      });
116
  }
117
}
118
119
module.exports = Model;
120